import IPoint from "../interface/IPoint"
import GridSystem from "../GridSystem"
import { CoordinateSystem, ControlPoint, LinkMark, MyEvent, BlockCategory, BlockType } from "../Constants";
import MyControlPoint from "./MyControlPoint";
import { getUuid, getRotatePoint } from "../utils"
import Node from "./Node";
import Line from "./Line";

class Block extends Node {

    id: string  // 唯一id
    name: string  //名称
    class: string;  // 元素类型名称

    // 元素基本属性
    gridCoord: IPoint;
    x: number  // x坐标
    y: number  // y坐标
    width: number  // 宽度
    height: number  // 高度
    fill: string; // 填充色
    opacity: number; // 填充色
    touchFill: string; // 填充色
    angle: number;  // 旋转角度
    zIndex: number;  // 层级关系
    text: string;  // 文字内容
    src: string | null;  // 图片地址
    category: BlockCategory  // 元素类型: 线性,方形,圆
    lastDist: IPoint | null;  // 记录之前移动过得距离
    rotatePoint: IPoint | null;  // 旋转的中心点

    // 节点关联元素
    controlPoints: MyControlPoint[];  // 控制点
    parentBlock: Block | Line | null; // 关联父元素
    transformPoint: Block | null // 是否在形变，放大缩小旋转
    isLinkMark: boolean  // 是否有连线, 是起点还是终点
    children: Block[];  // 子节点

    // 节点状态
    isPointIn: boolean //鼠标是否悬浮在元素上
    isFixedSize: boolean // 是否固定大小，不随网格缩放
    isFixedPos: boolean;  // 是否绝对位置.不跟随网格移动
    isGrouped: boolean // 是否拖拽中
    isFocus: boolean  // 是否获取到焦点
    isBindLink: boolean;  // 是否绑定了link线
    isDraged: boolean;  // 是否在拖拽中
    isTouch: boolean;  // 是否在拖拽中
    isObstacle: boolean;  // 是否是障碍

    // 节点功能
    cbSelect: boolean;  // 是否可被选择
    cbMove: boolean; // 是否可被移动
    cbTransform: boolean; // 是否调整, 缩放旋转等
    cbAdsorption: boolean;  // 是否开启吸附效果
    cbTouch: boolean;  // 是否碰撞检测

    // 节点事件
    mouseOn: Function | null;  // 如果有，鼠标悬浮后就会被调用
    mouseDown: Function | null;  // 如果有，鼠标点击后就会被调用
    mouseLeave: Function | null;  // 如果有，鼠标离开后就会被调用
    fisrtTouch: Function | null;  // 碰撞触发事件
    touching: Function | null;  // 碰撞触发事件

    constructor(x: number = 40, y: number = 40, width: number, height: number, fill?: string) {
        super();
        this.id = getUuid();
        this.name = "";
        this.class = ""

        this.gridCoord = { x: 0, y: 0 }
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.fill = fill || "rgba(22,119,255, .5)";
        this.opacity = 1;
        this.touchFill = "rgba(22,119,255, 1)";
        this.angle = 0;
        this.zIndex = 0;
        this.text = '';
        this.src = '';
        this.category = BlockCategory.RECT   // 默认是矩形
        this.lastDist = null;
        this.isFixedPos = false;
        this.rotatePoint = null;

        this.controlPoints = [];
        this.parentBlock = null;
        this.transformPoint = null;
        this.children = []

        this.isPointIn = false;
        this.isDraged = false;
        this.isFixedSize = false;
        this.isFocus = false;
        this.isGrouped = false;
        this.isLinkMark = false;
        this.isBindLink = false;
        this.isTouch = false;
        this.isObstacle = false;

        // 默认先读取全局配置
        this.cbAdsorption = GridSystem.cbAdsorption;
        this.cbTransform = GridSystem.cbTransform;
        this.cbSelect = GridSystem.cbSelect;
        this.cbMove = GridSystem.cbMove;
        this.cbTouch = GridSystem.cbTouch;

        this.mouseOn = null;
        this.mouseLeave = null;
        this.mouseDown = null;
        this.fisrtTouch = null;
        this.touching = null;

    }

    setParentBlock(block: Block | Line) {
        this.parentBlock = block;
    }

    // 以网格大小为单位进行定位
    setGridCoord(cx: number, cy: number) {
        // if (cx == 0 || cy == 0) {
        //     throw "参数不应该为0"
        // }
        if (cx < 0) {
            this.gridCoord.x = cx;
        } else {
            this.gridCoord.x = cx - 1;
        }
        if (cy < 0) {
            this.gridCoord.y = cy;
        } else {
            this.gridCoord.y = cy - 1;
        }

        this.x = (this.gridCoord.x * CoordinateSystem.GRID_SIZE) * CoordinateSystem.GRID_SIZE;
        this.y = (this.gridCoord.y * CoordinateSystem.GRID_SIZE) * CoordinateSystem.GRID_SIZE;
    }

    draw(x: number, y: number, width: number, height: number, angle?: number) { }  // 通用方法,绘制


    /**
     * 渲染子元素
     * @param px  父元素的绝对坐标
     * @param py  
     * @param children 父元素的子元素们
     */
    drawChildBlock(px: number, py: number, children: Block[]) {
        let that = this;
        children.forEach(block => {
            if (block.parentBlock) {
                let width = GridSystem.gls.getPixelSize(block.width)
                let height = GridSystem.gls.getPixelSize(block.height);
                let x1 = GridSystem.gls.getPixelSize(block.x);
                let y1 = GridSystem.gls.getPixelSize(block.y);
                let x = px + x1;  // 相对于父元素偏移多少个单位
                let y = py + y1;
                block.draw(x, y, width, height);
                if (block.children?.length > 0) {   // 如果还有子元素,继续递归
                    that.drawChildBlock(x, y, block.children)
                }
            }
        })
    }

    /**
     * 更新元素属性
     * @param x 
     * @param y 
     * @param width 
     * @param height 
     */
    update(x?: number, y?: number, width?: number, height?: number, angle?: number) {
        if (!this.parentBlock) {
            if (x) this.x = GridSystem.gls.getRelativePosX(x, this);
            if (y) this.y = GridSystem.gls.getRelativePosY(y, this);
        }
        if (angle) this.angle = angle;
        if (width) this.width = GridSystem.gls.getRelativeSize(width, this);
        if (height) this.height = GridSystem.gls.getRelativeSize(height, this);
        if (x != undefined && y != undefined) {
            this.drawChildBlock(x, y, this.children)  // 绘制嵌套的子元素坐标
            // 更新以网格为单位的坐标
            this.gridCoord.x = this.x / (CoordinateSystem.GRID_SIZE * CoordinateSystem.GRID_SIZE);
            if (this.x >= 0) {
                this.gridCoord.x++;
            }
            this.gridCoord.y = this.y / (CoordinateSystem.GRID_SIZE * CoordinateSystem.GRID_SIZE);
            if (this.y >= 0) {
                this.gridCoord.y++;
            }
            // console.log(`x:${this.gridCoord.x}, y:${this.gridCoord.y}`);
        }
    }

    /**
     * 获取中心点,默认是相对大小和相对坐标
     * @param x 
     * @param y 
     * @param width 
     * @param height 
     * @returns 
     */
    getCenterPoint(x: number = this.x, y: number = this.y, width: number = this.width, height: number = this.height): IPoint {
        return {
            x: x + width / 2,
            y: y + height / 2
        }
    }

    /**
     * 获得元素宽高比
     * @returns 
     */
    getRatio() {
        return this.width / this.height;
    }

    setControlPoints(x: number, y: number, width: number, height: number,) {
        if (this.cbTransform && !this.isFixedPos && !this.isFixedSize && this.cbMove && this.cbSelect && !this.isBindLink) {
            GridSystem.gls.setRectControls(this, x, y, width, height);
        }
    }

    /**
     * 设置元素旋转,默认旋转点是中心点
     * @param gls 
     * @param x 
     * @param y 
     * @param width 
     * @param height 
     * @param angle 
     * @param centerPoint 
     */
    setAngle(x: number, y: number, width: number, height: number, angle: number = this.angle) {
        let centerPoint;
        if (!this.rotatePoint) {
            centerPoint = this.getCenterPoint(x, y, width, height)
        } else {
            centerPoint = this.rotatePoint;
        }
        // centerPoint = {x,y};
        let ctx = GridSystem.gls.ctx;
        if (angle) {
            this.angle = angle;
            ctx.translate(centerPoint.x, centerPoint.y)
            ctx.rotate(this.angle * Math.PI / 180)
            ctx.translate(-centerPoint.x, -centerPoint.y)
        }
    }

    /**
     * 设置焦点高亮
     * @param gls 
     */
    setFocusStyle() {
        if (GridSystem.gls.focusNode && this === GridSystem.gls.focusNode && GridSystem.gls.cbDrawClass(this) && this.cbSelect) {
            let ctx = GridSystem.gls.ctx;
            ctx.save();
            ctx.lineWidth = 2;
            ctx.strokeStyle = "#000";
            ctx.stroke();
            ctx.restore();
        }
    }

    // 底部宽高文本
    setSizeInfo(x: number, y: number, width: number, height: number) {
        if (this.transformPoint && this.transformPoint) {
            let ctx = GridSystem.gls.ctx;
            let text = `w×h:${this.width.toFixed(2)} × ${this.height.toFixed(2)} | a:${this.angle.toFixed(2)}`
            ctx.fillStyle = '#595959';
            ctx.font = `16px Arial`;
            let textWidth = ctx.measureText(text).width;
            ctx.fillText(text, x + width / 2 - textWidth / 2, y + height + 25);
        }
    }

    setAdsorption(x: number, y: number, width: number, height: number): IPoint {
        if (this.cbAdsorption) {
            return this.setAdsorpte({ x, y })
        } else {
            return { x, y }
        }
    }

    /**
     * 网格吸附效果
     * @param gls 
     * @param point 
     * @returns 
     */
    setAdsorpte(point: IPoint): IPoint {
        if (GridSystem.gls.dragNode == this) {
            let gridSize = CoordinateSystem.GRID_SIZE * GridSystem.gls.scale;  // 实际网格单元大小

            let biggerX = (point.x - GridSystem.gls.pageSlicePos.x) / gridSize; // 从右向左靠近
            let biggerX2 = (point.x - GridSystem.gls.pageSlicePos.x + gridSize) / gridSize;  // 获得下一个相邻坐标, 从左向右靠近

            let remainderX = biggerX % 1; // 获得余数,获得实际误差

            if (biggerX > 0) {
                if (remainderX < CoordinateSystem.ERROR_RANGE) {
                    point.x = GridSystem.gls.pageSlicePos.x + Math.floor(biggerX) * gridSize;
                }
                if (remainderX > 1 - CoordinateSystem.ERROR_RANGE) {
                    point.x = GridSystem.gls.pageSlicePos.x + Math.floor(biggerX2) * gridSize;
                }
            }
            if (biggerX < 0) {
                if (remainderX < -(1 - CoordinateSystem.ERROR_RANGE)) {
                    point.x = GridSystem.gls.pageSlicePos.x + Math.floor(biggerX) * gridSize;
                }
                if (remainderX > - CoordinateSystem.ERROR_RANGE && remainderX < -.01) {   // remainderX < -.01 防止闪烁
                    point.x = GridSystem.gls.pageSlicePos.x + Math.floor(biggerX2) * gridSize;
                }
            }

            let biggerY = (point.y - GridSystem.gls.pageSlicePos.y) / gridSize; // 从右向左靠近
            let biggerY2 = ((point.y - GridSystem.gls.pageSlicePos.y + gridSize)) / gridSize;  // 获得下一个相邻坐标, 从左向右靠近
            let remainderY = biggerY % 1; // 获得余数

            if (biggerY > 0) {
                if (remainderY < CoordinateSystem.ERROR_RANGE) {
                    point.y = GridSystem.gls.pageSlicePos.y + Math.floor(biggerY) * gridSize;
                }
                if (remainderY > 1 - CoordinateSystem.ERROR_RANGE) {
                    point.y = GridSystem.gls.pageSlicePos.y + Math.floor(biggerY2) * gridSize;
                }
            }
            if (biggerY < 0) {
                if (remainderY < -(1 - CoordinateSystem.ERROR_RANGE)) {
                    point.y = GridSystem.gls.pageSlicePos.y + Math.floor(biggerY) * gridSize;
                }
                if (remainderY > - CoordinateSystem.ERROR_RANGE && remainderY < -.01) { // remainderY < -.01 防止闪烁
                    point.y = GridSystem.gls.pageSlicePos.y + Math.floor(biggerY2) * gridSize;
                }
            }

            GridSystem.gls.ctx.save();
            GridSystem.gls.ctx.strokeStyle = "#ff7875";
            GridSystem.gls.ctx.setLineDash([5, 10]);
            GridSystem.gls.ctx.beginPath();
            GridSystem.gls.ctx.moveTo(0, point.y);
            GridSystem.gls.ctx.lineTo(GridSystem.gls.canvasWidth, point.y);
            GridSystem.gls.ctx.moveTo(point.x, 0);
            GridSystem.gls.ctx.lineTo(point.x, GridSystem.gls.canvasHeight);
            GridSystem.gls.ctx.stroke();
        }
        return point;
    }

    drawLink(x: number, y: number, width: number, height: number) {
        if (this.isLinkMark) {
            let event;
            let centerPoint = this.getCenterPoint(x, y, width, height)
            event = new CustomEvent(MyEvent.DRAW_LINK, { detail: { x: centerPoint.x, y: centerPoint.y, block: this } });
            event && document.dispatchEvent(event);
        }
    }

    drawControls(rectX: number, rectY: number, rectWidth: number, rectHeight: number) {  // 实际像素        
        this.controlPoints.forEach(controlPoint => {
            controlPoint.angle = this.angle;
            let parentCenter = this.getCenterPoint(rectX, rectY, rectWidth, rectHeight);
            if (controlPoint.name == ControlPoint.LEFT_TOP_POINT) {  // 左上
                controlPoint.drawPonit(controlPoint.getLeftTopPointPosition(rectX, rectY), parentCenter)
            }
            if (controlPoint.name == ControlPoint.RIGHT_TOP_POINT) {  // 右上
                controlPoint.drawPonit(controlPoint.getRightTopPointPosition(rectX, rectY, rectWidth, rectHeight), parentCenter)
            }
            if (controlPoint.name == ControlPoint.LEFT_BOTTOM_POINT) { // 左下
                controlPoint.drawPonit(controlPoint.getLeftBottomPointPosition(rectX, rectY, rectWidth, rectHeight), parentCenter)
            }
            if (controlPoint.name == ControlPoint.RIGHT_BOTTOM_POINT) { // 右下
                controlPoint.drawPonit(controlPoint.getRightBottomPointPosition(rectX, rectY, rectWidth, rectHeight), parentCenter)
            }
            if (controlPoint.name == ControlPoint.ROTATE_POINT) { // 旋转点
                controlPoint.drawPonit(controlPoint.getRotatePointPosition(rectX, rectY, rectWidth, rectHeight), parentCenter)
            }
        })
    }

    /**
     * 绘制矩形
     * @param gls 
     * @param x 
     * @param y 
     * @param width 
     * @param height 
     */
    drawRect(x: number, y: number, width: number, height: number, fill: string = 'transparent') {
        let ctx = GridSystem.gls.ctx;
        ctx.save()
        ctx.beginPath();
        ctx.moveTo(x, y);
        ctx.lineTo(x + width, y);
        ctx.lineTo(x + width, y + height);
        ctx.lineTo(x, y + height);
        ctx.fillStyle = fill;
        ctx.fill();	//再填充
        ctx.closePath(); //闭合
        ctx.restore()
    }

    toFixedPos() {
        if (!this.isFixedPos) {
            let { x, y } = GridSystem.gls.getPixelPos({ x: this.x, y: this.y });
            this.x = x;
            this.y = y;
        }
        this.isFixedPos = true;
    }

    toFixedSize() {
        if (!this.isFixedSize) {
            this.width = GridSystem.gls.getPixelSize(this.width);
            this.height = GridSystem.gls.getPixelSize(this.height);
        }
        this.isFixedSize = true;
    }

    toRelativePos() {
        if (this.isFixedPos) {
            let { x, y } = GridSystem.gls.getRelativePos({ x: this.x, y: this.y });
            this.x = x;
            this.y = y;
        }
        this.isFixedPos = false;
    }

    toRelativeSize() {
        if (this.isFixedSize) {
            this.width = GridSystem.gls.getRelativeSize(this.width);
            this.height = GridSystem.gls.getRelativeSize(this.height);
        }
        this.isFixedSize = false;
    }

    // 嵌套子元素
    addBlock(block: Block) {
        block.parentBlock = this;
        this.children.push(block)
    }

    removeBlock() {

    }

    // 移除最后一个子元素
    popBlock() {
        this.children.pop()
    }
}
export default Block;